using JetBrains.Annotations;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEditor.Animations;
using UnityEngine;

[System.Serializable]
[RequireComponent(typeof(Animator))]
[RequireComponent(typeof(SpriteRenderer))]
[RequireComponent(typeof(C_BasicAttribute))]
public class C_AnimationController : C_Base
{
    [ReadOnly]
    public string curAnimName = "";
    public AnimatorController animatorController;
    public List<C_Anim> C_AnimList;

    private Dictionary<string, C_Anim> C_AnimDict = new Dictionary<string, C_Anim>();
    private string defaultAnimName = "";
    private C_Anim curAnim = null;
    private int curIndex = -1;
    private List<Coroutine> coroutineList = new List<Coroutine>();
    private KeyState attackState = new KeyState();
    private KeyState skillState = new KeyState();
    private bool canUpdate = false;

    private C_BasicAttribute basicAttribute;

    private SpriteRenderer spriteRenderer;
    private Animator animator;
    public override void OnAddComponent()
    {
        base.OnAddComponent();
        basicAttribute = GetComponent<C_BasicAttribute>();
        basicAttribute.OnAddComponent();
    }
    public override void Equip(params Object[] args)
    {
        base.Equip();
        attackState.Reset();
        skillState.Reset();
        SwitchToAnim(defaultAnimName);
    }
    public override void UnEquip(params Object[] args)
    {
        attackState.Reset();
        skillState.Reset();
        SwitchToAnim(defaultAnimName);
        base.UnEquip();
    }
    private void OnDestroy()
    {
        
    }

    private void Awake()
    {
        spriteRenderer = GetComponent<SpriteRenderer>();
        spriteRenderer.sortingLayerName = "Weapon";
        animator = GetComponent<Animator>();
    }
    private void Start()
    {

    }
    private void Update()
    {
        if (!canUpdate) return;
        var statenNormalizedTime = animator.GetCurrentAnimatorStateInfo(0).normalizedTime;
        var animInfo = curAnim.GetAnimInfo();
        if (statenNormalizedTime >= (float)(curIndex + 1) / animInfo.totalFrame)
        {
            OnAnimChangePerFrame();
        }
    }
    public void SetAttackPressed(int pressed)
    {
        attackState.pressed = pressed;
    }
    public void SetSkillPressed(int pressed)
    {
        skillState.pressed = pressed;
    }
    public void SetAttackValid(bool valid)
    {
        if (valid && attackState.isValid < 0)
        {
            attackState.isValid++;
        }
        else if (!valid)
        {
            attackState.isValid--;
        }

    }
    public void SetSkillValid(bool valid)
    {
        if (valid && skillState.isValid < 0)
        {
            skillState.isValid++;
        }
        else if (!valid)
        {
            skillState.isValid--;
        }
    }

    /// <summary>
    /// 得到动画名称列表
    /// </summary>
    /// <returns></returns>
    public List<string> GetAnimNameList()
    {
        List<string> list = new List<string>();
        C_AnimList.ForEach((anim) =>
        {
            list.Add(anim.C_AnimName);
        });
        return list;
    }
    public override void Init(params UnityEngine.Object[] args)
    {
        //string path = $"Assets/Animations/ComponentAnimationController/{GetComponent<C_BasicAttribute>().C_Name + "_" + GetComponent<C_BasicAttribute>().C_HolderGO.name}.controller";
        //ac = AnimatorController.CreateAnimatorControllerAtPath(path);
        //AssetDatabase.SaveAssets();
        //AssetDatabase.Refresh();
        //AnimatorStateMachine asm = ac.layers[0].stateMachine;
        //foreach (C_Anim anim in C_AnimList)
        //{
        //    anim.InitAnimEvent();
        //    if (anim.C_AnimClip == null) return;
        //    AnimationClip clip = anim.C_AnimClip;
        //    AnimatorState aState = asm.AddState(anim.C_AnimName);
        //    aState.motion = clip;
        //    if (anim.C_IsDefaultAnim)
        //    {
        //        asm.defaultState = aState;
        //        defaultAnimName = anim.C_AnimName;
        //    }
        //    if (!C_AnimDict.ContainsKey(anim.C_AnimName)) C_AnimDict.Add(anim.C_AnimName, anim);
        //}
        //animator.runtimeAnimatorController = ac;
        AnimatorStateMachine asm = animatorController.layers[0].stateMachine;
        List<AnimationClip> clipList = animatorController.animationClips.ToList();
        foreach (C_Anim anim in C_AnimList)
        {
            if (anim.C_AnimClip == null)
            {
                anim.C_AnimClip = clipList.Find(x => x.name == anim.C_AnimName);
            }
            anim.InitAnimEvent();
            if (anim.C_IsDefaultAnim)
            {
                ChildAnimatorState[] cas = asm.states;
                AnimatorState aState = cas.ToList().Find(x => x.state.name == anim.C_AnimName).state;
                asm.defaultState = aState;
                defaultAnimName = anim.C_AnimName;
            }
            if (!C_AnimDict.ContainsKey(anim.C_AnimName)) C_AnimDict.Add(anim.C_AnimName, anim);
        }
        animator.runtimeAnimatorController = animatorController;
        base.Init();
    }
    public void SwitchToAnim(string targetAnimName)
    {
        curIndex = -1;
        foreach (var item in coroutineList)
        {
            if (item == null) continue;
            StopCoroutine(item);
        }
        coroutineList.Clear();
        if (C_AnimDict.ContainsKey(targetAnimName))
        {
            curAnim = C_AnimDict[targetAnimName];
            curAnimName = curAnim.C_AnimName;
            DoAnimEventByTag(AnimEventType.Start);
            animator.Play(curAnim.C_AnimName, 0, 0);
            animator.speed = basicAttribute.GetHolderData().GetAttackSpeedScale();
            canUpdate = true;
        }
    }
    public void DoAnimEventByTag(AnimEventType type)
    {
        if (curAnim != null)
        {
            List<C_AnimEvent> animList = curAnim.GetAnimEventByType(type);
            if (animList != null)
            {
                foreach (var animEvent in animList)
                {
                    GetAnimEventCallbackByFunc(animEvent)?.Invoke();
                    GetAnimEventCallbackBySwitchAnim(animEvent)?.Invoke();
                }
            }
        }
    }
    public void OnAnimChangePerFrame()
    {
        if (GameManager.Instance.curState != GameState.Gaming) return;
        curIndex++;
        if (curIndex < curAnim.GetAnimInfo().totalFrame)
        {
            List<C_AnimEvent> animEventList = curAnim.GetAnimEventFrameDict()[curIndex];
            if (animEventList != null)
            {
                bool attackPressed = false;
                bool skillPressed = false;
                foreach (var animEvent in animEventList)
                {
                    if (animEvent.type == AnimEventType.Interrupt)
                    {
                        GetAnimEventCallbackByFunc(animEvent)?.Invoke();
                        GetAnimEventCallbackBySwitchAnim(animEvent)?.Invoke();
                    }
                    else if (animEvent.type == AnimEventType.StartAttack && attackState.pressed == 1 && attackState.isValid == 0)
                    {
                        gameObject.transform.parent.BroadcastMessage("EndReload", SendMessageOptions.DontRequireReceiver);
                        GetAnimEventCallbackByFunc(animEvent)?.Invoke();
                        GetAnimEventCallbackBySwitchAnim(animEvent)?.Invoke();
                    }
                    else if (animEvent.type == AnimEventType.EndAttack && attackState.pressed == -1 && attackState.isValid == 0)
                    {
                        GetAnimEventCallbackByFunc(animEvent)?.Invoke();
                        GetAnimEventCallbackBySwitchAnim(animEvent)?.Invoke();
                        attackPressed = true;
                    }
                    else if (animEvent.type == AnimEventType.StartSkill && skillState.pressed == 1 && skillState.isValid == 0)
                    {
                        GetAnimEventCallbackByFunc(animEvent)?.Invoke();
                        GetAnimEventCallbackBySwitchAnim(animEvent)?.Invoke();
                    }
                    else if (animEvent.type == AnimEventType.EndSkill && skillState.pressed == -1 && skillState.isValid == 0)
                    {
                        GetAnimEventCallbackByFunc(animEvent)?.Invoke();
                        GetAnimEventCallbackBySwitchAnim(animEvent)?.Invoke();
                        skillPressed = true;
                    }
                }
                attackState.pressed = attackPressed ? 0 : attackState.pressed;
                skillState.pressed = skillPressed ? 0 : skillState.pressed;
            }
        }

        if (!curAnim.C_IsLoop && curIndex >= curAnim.GetAnimInfo().totalFrame)
        {
            canUpdate = false;
            DoAnimEventByTag(AnimEventType.End);
        }
        else if (curAnim.C_IsLoop && curIndex >= curAnim.GetAnimInfo().totalFrame)
        {
            canUpdate = false;
            SwitchToAnim(curAnim.C_AnimName);
        }

    }
    #region 得到事件回调
    public System.Action GetAnimEventCallbackBySwitchAnim(C_AnimEvent animEvent)
    {
        if (!animEvent.hasSwitchAnim || !C_AnimDict.ContainsKey(animEvent.switchAnim)) return null;
        System.Action callback = () => { SwitchToAnim(animEvent.switchAnim); };
        if (!animEvent.isSwitchDelay)
        {
            return callback;
        }
        return () =>
        {
            coroutineList.Add(StartCoroutine(Coro_AnimEvent(callback, animEvent.switchDelayTime)));
        };
    }
    public System.Action GetAnimEventCallbackByFunc(C_AnimEvent animEvent)
    {
        if (!animEvent.hasFunc || animEvent.animFuncList.Count == 0) return null;
        System.Action callback = () =>
        {
            foreach (var func in animEvent.animFuncList)
            {
                if (func.hasVariable)
                {
                    SendMessage(func.funcName, func.variable.GetVariable());
                }
                else
                {
                    SendMessage(func.funcName);
                }
            }
        };
        if (!animEvent.isSwitchDelay)
        {
            return callback;
        }
        return () =>
        {
            coroutineList.Add(StartCoroutine(Coro_AnimEvent(callback, animEvent.funcDelayTime)));
        };
    }
    #endregion

    IEnumerator Coro_AnimEvent(System.Action callback, float delayTime = 0f)
    {
        if (delayTime > 0f)
        {
            yield return new WaitForSeconds(delayTime);
        }
        callback?.Invoke();
    }
    IEnumerator Coro_AnimEvent<T>(System.Action<T> callback, T param, float delayTime = 0f)
    {
        if (delayTime > 0f)
        {
            yield return new WaitForSeconds(delayTime);
        }
        callback?.Invoke(param);
    }
}
public class KeyState
{
    public int pressed = 0;
    public int isValid = 0;
    public void Reset()
    {
        pressed = 0;
        isValid = 0;
    }
}
